#include "gd32h7xx.h"
#include <stdio.h>
#include "gd32h759i_eval.h"
#include "systick.h"
#include "string.h"

#define BUFFER_SIZE        8U
#define UART_CMD_BUFFER_SIZE 32
#define MIN_DURATION_MS    1U  // 最小时间差，避免除零错误

/* 全局变量 */
uint8_t rx_data[BUFFER_SIZE];      // 接收数据缓冲区
uint8_t tx_data[BUFFER_SIZE];      // 发送数据缓冲区
can_mailbox_descriptor_struct receive_message;  // 接收邮箱描述符
can_mailbox_descriptor_struct transmit_message; // 发送邮箱描述符
volatile uint32_t frame_count = 0;
volatile uint32_t last_frame_count = 0;
volatile uint64_t last_time = 0;         // 微秒级时间
volatile uint32_t max_frames_per_sec = 0;
volatile float max_bus_load = 0.0f;
volatile FlagStatus test_started = RESET;
char uart_cmd_buffer[UART_CMD_BUFFER_SIZE];
uint8_t uart_cmd_index = 0;
volatile uint64_t test_start_time = 0;   // 测试开始时间（微秒级）
volatile uint64_t test_end_time = 0;     // 测试结束时间（微秒级）

/* 函数声明 */
void can_gpio_config(void);
void bsp_board_config(void);
void can_config(void);
void communication_check(void);
void cache_enable(void);
void print_test_status(void);
void print_test_results(void);
uint64_t get_micros(void);
void process_uart_command(void);
FlagStatus is_all_zero_data(void);
void reset_test_data(void);

/* 获取微秒级时间（使用SysTick计数器） */
uint64_t get_micros(void) {
    static uint64_t ticks = 0;
    static uint32_t last_val = 0;
    uint32_t val = SysTick->VAL;
    uint32_t load = SysTick->LOAD;
    
    // SysTick是递减计数器，计算两次调用之间的差值
    if (val < last_val) {
        // 计数器溢出，累加差值
        ticks += (last_val - val);
    } else {
        // 计数器未溢出，累加（LOAD - val + last_val）
        ticks += (load - val + last_val);
    }
    last_val = val;
    
    // 转换为微秒（假设SystemCoreClock为系统主频，单位Hz）
    return (ticks * 1000000ULL) / SystemCoreClock;
}

/* 检查全零数据 */
FlagStatus is_all_zero_data(void) {
    for (int i = 0; i < BUFFER_SIZE; i++) {
        if (rx_data[i] != 0) {
            return RESET;
        }
    }
    return SET;
}

/* 重置测试数据 */
void reset_test_data(void) {
    frame_count = 0;
    last_frame_count = 0;
    max_frames_per_sec = 0;
    max_bus_load = 0.0f;
    test_start_time = 0;
    test_end_time = 0;
    last_time = 0;
    test_started = RESET;
}

/* 处理串口指令 */
void process_uart_command(void) {
    uart_cmd_index = 0;
}

/* 打印测试状态 */
void print_test_status(void) {
    if (!test_started) return;
    
    uint64_t current_time = get_micros();
    uint64_t elapsed_us = current_time - last_time;
    
    // 至少等待1000微秒（1毫秒）再计算，避免除零
    if (elapsed_us >= 1000) {
        // 计算每秒帧数（帧率）：(帧数差 * 1e6) / 微秒差
        uint32_t frames_per_sec = (uint32_t)(((frame_count - last_frame_count) * 1000000ULL) / elapsed_us);
        last_frame_count = frame_count;
        last_time = current_time;

        if (frames_per_sec > max_frames_per_sec) {
            max_frames_per_sec = frames_per_sec;
        }

        // 总线负载计算
        float bus_load = (frames_per_sec * 111.0f * 100.0f) / 1000000.0f;
        if (bus_load > max_bus_load) {
            max_bus_load = bus_load;
        }

        printf("\r\nCurrent: %u frames/sec | Total: %u frames", frames_per_sec, frame_count);
        printf(" | Max Rate: %u | Max Load: %.2f%%", max_frames_per_sec, max_bus_load);
    }
}

/* 打印测试结果 */
void print_test_results(void) {
    // 计算测试总时长（微秒）
    uint64_t test_duration_us = test_end_time - test_start_time;
    // 转换为毫秒（确保至少1毫秒）
    uint32_t test_duration_ms = (uint32_t)(test_duration_us / 1000);
    if (test_duration_ms < MIN_DURATION_MS) {
        test_duration_ms = MIN_DURATION_MS;
    }

    // 计算总帧率：(总帧数 * 1e6) / 总时长（微秒）
    uint32_t final_fps = 0;
    if (test_duration_us > 0) {
        final_fps = (uint32_t)((frame_count * 1000000ULL) / test_duration_us);
    }

    // 总线负载
    float final_load = (final_fps * 111.0f * 100.0f) / 1000000.0f;
    
    // 更新最大值
    if (final_fps > max_frames_per_sec) {
        max_frames_per_sec = final_fps;
    }
    if (final_load > max_bus_load) {
        max_bus_load = final_load;
    }

    printf("\r\n\r\nTest Results:\r\n");
    printf("Total Frames: %u\r\n", frame_count);
    printf("Test Duration: %u ms (%.3f sec)\r\n", test_duration_ms, test_duration_ms / 1000.0f);
    printf("Max Frame Rate: %u frames/sec\r\n", max_frames_per_sec);
    printf("Max Bus Load: %.2f%%\r\n", max_bus_load);
    printf("Waiting for new test data...\r\n");
}

int main(void) {
    /* 系统初始化 */
    cache_enable();
    systick_config();  // 初始化SysTick定时器
    bsp_board_config();
    can_gpio_config();
    can_config();

    /* 初始化CAN接收邮箱 */
    can_struct_para_init(CAN_MDSC_STRUCT, &receive_message);
    receive_message.rtr = 0U;        // 数据帧
    receive_message.ide = 0U;        // 标准ID
    receive_message.code = CAN_MB_RX_STATUS_EMPTY;
    receive_message.id = 0x55U;      // 接收ID=0x55的帧
    receive_message.data = (uint32_t *)(rx_data);
    receive_message.data_bytes = BUFFER_SIZE;
    can_mailbox_config(CAN1, 0U, &receive_message);
    
    /* 初始化CAN发送邮箱 */
    can_struct_para_init(CAN_MDSC_STRUCT, &transmit_message);
    transmit_message.rtr = 0U;        // 数据帧
    transmit_message.ide = 0U;        // 标准ID
    transmit_message.code = CAN_MB_TX_STATUS_DATA; // 发送数据状态
    transmit_message.brs = 0U;       // 位速率切换禁用
    transmit_message.fdf = 0U;       // 经典CAN帧
    transmit_message.prio = 0U;       // 优先级
    transmit_message.data_bytes = BUFFER_SIZE;
    transmit_message.id = 0xAAU;     // 发送ID=0xAA的帧

    /* 使能CAN1中断 */
    can_interrupt_enable(CAN1, CAN_INT_MB0);

    printf("\r\nCAN1 Frame Rate Test Started\r\n");
    printf("Stop condition: All-zero data (00 00 00 00 00 00 00 00)\r\n");
    printf("Waiting for data...\r\n");

    reset_test_data();  // 初始重置
    last_time = get_micros();  // 初始化时间（微秒）

    /* 主循环 */
    while (1) {
        uint64_t current_time = get_micros();
        
        /* 每2秒打印一次状态（2000000微秒） */
        if (test_started && (current_time - last_time >= 2000000)) {
            print_test_status();
        }
        
        /* 检查串口输入 */
        if (usart_flag_get(EVAL_COM, USART_FLAG_RBNE) != RESET) {
            char ch = usart_data_receive(EVAL_COM);
            if (ch == '\r' || ch == '\n') {
                process_uart_command();
            } else if (uart_cmd_index < UART_CMD_BUFFER_SIZE - 1) {
                uart_cmd_buffer[uart_cmd_index++] = ch;
            }
        }

        communication_check();
    }
}

/* 配置CAN GPIO引脚 */
void can_gpio_config(void) {
    rcu_can_clock_config(IDX_CAN1, RCU_CANSRC_APB2);
    rcu_periph_clock_enable(RCU_CAN1);
    rcu_periph_clock_enable(RCU_GPIOB);

    /* CAN1_RX: PB5 */
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_5);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);
    gpio_af_set(GPIOB, GPIO_AF_9, GPIO_PIN_5);

    /* CAN1_TX: PB13 */
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_13);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_13);
    gpio_af_set(GPIOB, GPIO_AF_9, GPIO_PIN_13);
}

/* 板级配置 */
void bsp_board_config(void) {
    gd_eval_com_init(EVAL_COM);
    gd_eval_led_init(LED2);
    gd_eval_led_off(LED2);
    printf("UART initialized: 115200 bps\r\n");
}

/* 配置CAN控制器 */
void can_config(void) {
    can_parameter_struct can_parameter;
    can_deinit(CAN1);
    can_struct_para_init(CAN_INIT_STRUCT, &can_parameter);

    /* CAN通用参数 */
    can_parameter.internal_counter_source = CAN_TIMER_SOURCE_BIT_CLOCK;
    can_parameter.self_reception = DISABLE;
    can_parameter.mb_tx_order = CAN_TX_HIGH_PRIORITY_MB_FIRST;
    can_parameter.mb_tx_abort_enable = ENABLE;
    can_parameter.local_priority_enable = DISABLE;
    can_parameter.mb_rx_ide_rtr_type = CAN_IDE_RTR_FILTERED;
    can_parameter.mb_remote_frame = CAN_STORE_REMOTE_REQUEST_FRAME;
    can_parameter.rx_private_filter_queue_enable = DISABLE;
    can_parameter.edge_filter_enable = DISABLE;
    can_parameter.protocol_exception_enable = DISABLE;
    can_parameter.rx_filter_order = CAN_RX_FILTER_ORDER_MAILBOX_FIRST;
    can_parameter.memory_size = CAN_MEMSIZE_32_UNIT;
    can_parameter.mb_public_filter = 0U;

    /* 波特率配置 */
    can_parameter.resync_jump_width = 1U;
    can_parameter.prop_time_segment = 2U;
    can_parameter.time_segment_1 = 5U;
    can_parameter.time_segment_2 = 2U;
    can_parameter.prescaler = 30U;
    can_init(CAN1, &can_parameter);

    /* 使能CAN1中断 */
    nvic_irq_enable(CAN1_Message_IRQn, 0U, 0U);
    can_operation_mode_enter(CAN1, CAN_NORMAL_MODE);

    /* 检查CAN模式 */
    if (can_operation_mode_get(CAN1) == CAN_NORMAL_MODE) {
        printf("CAN1 initialized in normal mode\r\n");
    } else {
        printf("CAN1 failed to enter normal mode!\r\n");
    }
}

/* 通信状态检查 */
void communication_check(void) {
    if (test_started && (frame_count % 1000 == 0) && frame_count > 0) {
        gd_eval_led_toggle(LED2);
    }
}

/* 使能Cache */
void cache_enable(void) {
    SCB_EnableICache();
    SCB_EnableDCache();
}

/* CAN1中断处理函数 */
void CAN1_Message_IRQHandler(void) {
    if (SET == can_interrupt_flag_get(CAN1, CAN_INT_FLAG_MB0)) {
        can_interrupt_flag_clear(CAN1, CAN_INT_FLAG_MB0);
        can_mailbox_receive_data_read(CAN1, 0U, &receive_message);

        // 首次接收数据时记录开始时间（微秒级）
        if (frame_count == 0) {
            test_start_time = get_micros();
            last_time = test_start_time;
            test_started = SET;  // 标记测试开始
        }

        if (is_all_zero_data()) {
            test_started = RESET;
            test_end_time = get_micros();  // 记录结束时间（微秒级）
            
            // 打印结果并重置
            print_test_results();
            reset_test_data();
            printf("\r\nNew test can start now\r\n");
            printf("Stop condition: All-zero data (00 00 00 00 00 00 00 00)\r\n");
        } else {
            frame_count++;  // 计数有效帧
            
            // 将接收到的数据复制到发送缓冲区
            memcpy(tx_data, rx_data, BUFFER_SIZE);
            
            // 配置发送邮箱数据指针
            transmit_message.data = (uint32_t *)tx_data;
            
            // 发送数据回上位机
            can_mailbox_config(CAN1, 1U, &transmit_message); // 使用邮箱1发送
        }
    }
}

/* 重定向printf到串口 */
int fputc(int ch, FILE *f) {
    usart_data_transmit(EVAL_COM, (uint8_t)ch);
    while (RESET == usart_flag_get(EVAL_COM, USART_FLAG_TBE));
    return ch;
}